// Copyright 2012 dmitry.a.novikov@gmail.com
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "consistenz.h"
#include "dbdictionary.h"
#include "dbdictionaryimpl.h"
#include "filer.h"
#include <iostream>



namespace CnsZ {

  //#define TEMPL_IMPL_FACTORY(Cls) return ImplRefCount<##Cls##Impl<Cls>, Object>::New()

  DEFINE_CNSZ_DBCLASS(DDictionary, DObject, DBOBJECT_FACTORY);

  //  DEFINE_CNSZ_CLASS(ObjectIterator, Object, NULL_FACTORY);

  DDictionary::DDictionary() : DObject(new DDictionaryImpl) {
  }

  DDictionary::~DDictionary() {
    delete static_cast<DDictionaryImpl*>(impl);
  }

  void DDictionary::putAt(const Object* id, Object* object, P<Object>* replaced) {
    DDictionaryImpl* impl = static_cast<DDictionaryImpl*>(this->impl);
    impl->putAt(id, object, replaced);
  }

  size_t DDictionary::size() const {
    DDictionaryImpl* impl = static_cast<DDictionaryImpl*>(this->impl);
    return impl->size();
  }

  bool DDictionary::has(const Object* id) const {
    DDictionaryImpl* impl = static_cast<DDictionaryImpl*>(this->impl);
    return impl->has(id);
  }

  P<Object> DDictionary::getAt(const Object* id) const {
    DDictionaryImpl* impl = static_cast<DDictionaryImpl*>(this->impl);
    return impl->getAt(id);
  }

  P<ObjectIterator> DDictionary::newIterator(const Object* subsetFrom, const Object* subsetTo) const {
    return static_cast<DDictionaryImpl*>(this->impl)->newIterator(this, subsetFrom, subsetTo);
  }
  
  void DDictionary::attachToHandleAt(const Object* id, DObject* dobject, P<Object>* replaced) {
    DDictionaryImpl* impl = static_cast<DDictionaryImpl*>(this->impl);
    DictionaryItem* item = impl->find(id);
    if(item) {
      P<Object> existing = item->object;
      if(replaced) {
        *replaced = existing;
      }

      item->object = domain()->attach(dobject, handle());
    }
    putAt(id, domain()->attach(dobject, handle()));
  }

  //void DDictionary::addReactor(DictionaryReactor* reactor) = 0;

  //void DDictionary::removeReactor(DictionaryReactor* reactor) = 0;

  void DDictionary::read(Filer& filer) {
    DObject::read(filer);
    Int64 sz = filer.rdInt64();
    while(sz--) {
      P<Object> id = filer.rdObject();
      P<Object> obj = filer.rdObject();
      putAt(id, obj);
    }
  }

  void DDictionary::write(Filer& filer) const {
    DObject::write(filer);
    P<ObjectIterator> iter = newIterator();
    filer.wrInt64(size());
    while(!iter->done()) {
      filer.wrObject(iter->identifer());
      filer.wrObject(iter->object());
      iter->next();
    }
  }

  String DDictionary::toString() const {
    DDictionaryImpl* impl = static_cast<DDictionaryImpl*>(this->impl);
    return impl->toString();
  }

  /*
  void DictionaryReactor::added(const Handle* ) {}

  void DictionaryReactor::removed(const Handle* ) {}

  void DictionaryReactor::willBeModified(const Object* ) {}

  void DictionaryReactor::modified(const Handle* ) {}

  void DictionaryReactor::canceled(const Handle* ) {}
  */

}
